package com.mew.chess.core.game.bjl.game.task;

import com.mew.chess.core.common.handler.ChessPushMessageUtil;
import com.mew.chess.core.common.provide.GameFeignService;
import com.mew.chess.core.common.utils.ChessGameUtil;
import com.mew.chess.core.game.bjl.game.BjlGameManager;
import com.mew.chess.core.game.bjl.game.BjlRoomManager;
import com.mew.chess.core.game.bjl.game.common.BjlBetType;
import com.mew.chess.core.game.bjl.game.common.BjlConstantValue;
import com.mew.chess.core.game.bjl.game.common.BjlLinkType;
import com.mew.chess.core.game.bjl.game.common.BjlPushCMDMapType;
import com.mew.chess.core.game.bjl.game.message.PaymentMessage;
import com.mew.chess.core.game.bjl.game.message.PushPaymentMessage;
import com.mew.chess.core.game.bjl.game.message.UserMessage;
import com.mew.common.dc.redis.AucRedisService;
import com.mew.common.dc.redis.GameRoomRedisService;
import com.mew.common.enm.UserType;
import com.mew.common.entity.config.Room;
import com.mew.common.entity.game.RoomProfile;
import com.mew.common.rest.game.BetAfterRequest;
import com.zebra.common.concurrent.ZebraExecutorManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**赔付阶段
 * @author dylin
 * @create 2021/4/22
 */
@Component
@Slf4j
public class BjlPaymentTask {
    @Autowired
    private GameRoomRedisService gameRoomRedisService;
    @Autowired
    private GameFeignService feignService;
    @Autowired
    private AucRedisService aucRedisService;
    /**
     * 赔付
     * @param roomId
     * @return 是否需要洗牌
     */
    public void payment(int roomId){
        BjlRoomManager roomManager =BjlGameManager.getInstance().getController(roomId);
        payment(roomManager);
        roomManager.changeLink(BjlLinkType.Payment.code(),BjlConstantValue.PAYMENT_TIME);
        roomManager.setNeedInit(true);
        roomManager.addHistory();
        sendPaymentMsg(roomManager);
        pushLog(roomManager);
    }
    private void payment(BjlRoomManager roomManager){
        Room room = gameRoomRedisService.getRedisRoom(roomManager.getGameId(), roomManager.getRoomId());
        List<Integer> winList = roomManager.getBjlResult().getWinList();
        Collection<UserMessage> userList=roomManager.getPlayerList().values();
        for (UserMessage userMessage : userList) {
            validWin(userMessage,winList,room);
            userMessage.playTimes();
        }
        computePayment(roomManager,room);

    }
    private void validWin(UserMessage userMessage,List<Integer> winList, Room room){
        for (Map.Entry<Integer, long[]> entry : userMessage.getBetRecord().entrySet()) {
            if(winList.contains(entry.getKey())){
                BjlBetType betType=BjlBetType.parse(entry.getKey());
                long payment = entry.getValue()[0]*betType.rate()/100;
                int tax = 0;
                entry.getValue()[1] = payment-tax;
                entry.getValue()[2] = tax;
            }
        }
    }

    private void computePayment(BjlRoomManager roomManager, Room room){
        RoomProfile roomProfile = gameRoomRedisService.getRoomProfile(roomManager.getRoomId());
        List<BetAfterRequest> list = new ArrayList<>();
        roomManager.getPlayerList().values().stream().forEach(u->{
            if(u.getBetRecord().size()>0) {
                long bet = 0;
                long payment = 0;
                int tax = 0;
                long computePayment = 0;
                StringBuffer bets=new StringBuffer();
                StringBuffer payments=new StringBuffer();

                for (Map.Entry<Integer, long[]> entry : u.getBetRecord().entrySet()) {
                    long[] r=entry.getValue();
                    bet+=r[0];
                    payment+=r[1];
                    computePayment+=r[1]>0?r[1]+r[0]:0;
                    tax += r[2];
                    bets.append(entry.getKey()).append("_").append(r[0]).append(";");
                    payments.append(entry.getKey()).append("_").append(r[1]).append(";");
                }
                u.setPayment(computePayment);
                u.updateGoldNumber(0,computePayment);
                if(u.getUserType()!=UserType.Robot.code()){
                    list.add(builPlayRecord(roomManager,u,room,roomProfile,bet,payment,computePayment,tax,bets.toString(),payments.toString()));
                }
            }
            log.info("---payment : user:{}", u.getGameSession());
        });
        persistenceData(list);
    }


    private void persistenceData(List<BetAfterRequest> list){
        int size = list.size();
        if (size < 30){
            ZebraExecutorManager.getInstance().getDefaultExecutor().execute(() -> {
                feignService.chessBetAfter(list);
            });
            return;
        }


        ZebraExecutorManager.getInstance().getDefaultExecutor().execute(() -> {
            int s = 30;
            int c = (size / s) + 1;
            try {
                for (int i=0; i<c && i*s < size; i++){
                    TimeUnit.MILLISECONDS.sleep(200);
                    List<BetAfterRequest> subList = list.stream().skip(i*s).limit(s).collect(Collectors.toList());
                    feignService.chessBetAfter(subList);
                }
            } catch (InterruptedException e) {
            }
        });
    }
    //TODO
    private BetAfterRequest builPlayRecord(BjlRoomManager roomManager, UserMessage userMessage,Room room,
                RoomProfile roomProfile,long bet,long payment,long computePayment,int tax,String bets,String payments){
        BetAfterRequest request = BetAfterRequest.builder()
                .uid(userMessage.getUserId())
                .relateInoutId(userMessage.getGameSession().getInoutId())
                .gameId(roomManager.getGameId())
                .roomId(roomManager.getRoomId())
                .bet(bet)
                .payment(computePayment)
                .betTimes((int)(payment / bet))
                .roomRecord(1)
                .iconResult(roomManager.getBjlResult().getWinList().toString())
/*                .bloodBalance(room.getStratBloodBalance())
                .bloodValue(roomProfile.getBloodValue())*/
                .betArray(bets)
                .paymentArray(payments)
                .tax(tax)
                .build();

        return request;
    }
    private void sendPaymentMsg(BjlRoomManager roomManager){
        roomManager.getOnlineUser().forEach((k, v) -> {
            PushPaymentMessage pushPaymentMessage=new PushPaymentMessage();
            pushPaymentMessage.setHistoryMessageList(roomManager.getHistoryList());
            pushPaymentMessage.setWinList(roomManager.getBjlResult().getWinList());
            pushPaymentMessage.setBigPlayerPayment(buildBigPlayerPaymentMap(roomManager));
            UserMessage userMessage = roomManager.getPlayer(k);
            pushPaymentMessage.setPayment(userMessage.getPayment());
            pushPaymentMessage.setGoldNumber(userMessage.getGoldNumber());
            ChessPushMessageUtil.pushMessage(v, BjlPushCMDMapType.PaymentMessage.code(), pushPaymentMessage);
        });
    }

    private void pushLog(BjlRoomManager roomManager){
       roomManager.getPlayerList().values().stream().filter(u -> u.getUserType()!=UserType.Robot.code()&&u.getAllBet()>0).forEach(u->{
           long[] bets=new long[BjlBetType.values().length];
           long[] payments=new long[BjlBetType.values().length];
           for (int i = 0; i < BjlBetType.values().length; i++) {
               if(u.getBetRecord().get(i)!=null){
                   bets[i]=u.getBetRecord().get(i)[0];
                   payments[i]=u.getBetRecord().get(i)[1];
               }
           }
           ChessGameUtil.hpLog(
                   roomManager.getIno(),
                   u.getGameSession(),
                   bets,
                   payments,
                   roomManager.getBjlResult().getWinList().stream().mapToInt(Integer::intValue).toArray());
       });
    }

    /**
     * 构建大玩家赔付列表
     * @param roomManager
     * @return
     */
    private List<PaymentMessage> buildBigPlayerPaymentMap(BjlRoomManager roomManager){
        List<PaymentMessage> rs=new ArrayList<>();
        roomManager.getBigRList().values().stream().forEach(u->{
            if(u.getPayment()>0){
                rs.add(PaymentMessage.builder().uid(u.getUserId()).payment(u.getPayment()).build());
            }
        });
        return rs;
    }
}
